import os
import sys
import click
from flask import Flask,render_template,url_for
from flask import flash,redirect,request,abort
from flask_login import LoginManager,UserMixin,login_user,login_required,logout_user,current_user
from werkzeug.security import generate_password_hash,check_password_hash
from flask_sqlalchemy import SQLAlchemy

## 初始化扩展:app,db [10- 32]
WIN = sys.platform.startswith('win')
if WIN:
    prefix = 'sqlite:///'
else:
    prefix = 'sqlite:////'

app = Flask(__name__)

# db_path = os.path.abspath(os.path.join(app.root_path, "data.db"))
# db_dir = os.path.dirname(db_path)
# if not os.path.exists(db_dir):
#     os.makedirs(db_dir)

app.config['SQLALCHEMY_DATABASE_URI'] = prefix + os.path.join(app.root_path, 'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # 关闭对模型修改的监控
app.config['SECRET_KEY'] = 'dev'  # 等同于 app.secret_key = 'dev'
db = SQLAlchemy(app)

# with app.app_context():
#     db.create_all()

## 数据模型：Movie User [32-54]
class User(db.Model,UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20))
    username = db.Column(db.String(20))  # 用户名
    password_hash = db.Column(db.String(192))

    def set_password(self,password):
        pw_hash = generate_password_hash(password)
        if len(pw_hash) > 192:
            raise ValueError("Generated hash exceeds maximum length")
        self.password_hash = pw_hash
        
    def validate_password(self,password):
        return check_password_hash(self.password_hash,password)


class Movie(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(60))
    year = db.Column(db.String(4))


## shell命令行(command):initdb,forge,admin [55-125]
@app.cli.command()
@click.option("--drop",is_flag=True,help="Create after drop ")
def initdb(drop):
    """ Initialize the database"""
    if drop:
        db.drop_all()
    db.create_all()
    click.echo(" ---Initialize The Database Done--- ")


login_manager = LoginManager(app)
login_manager.login_view = 'login'
@login_manager.user_loader
def loader_user(user_id):
    user = User.query.get(int(user_id))
    return user


@app.cli.command()
def forge():
    """Generate fake data """
    db.create_all()
    ## 准备一些虚拟数据
    name = 'haiShen'
    movies = [
        {'title': 'My Neighbor Totoro', 'year': '1988'},
        {'title': 'Dead Poets Society', 'year': '1989'},
        {'title': 'A Perfect World', 'year': '1993'},
        {'title': 'Leon', 'year': '1994'},
        {'title': 'Mahjong', 'year': '1996'},
        {'title': 'Swallowtail Butterfly', 'year': '1996'},
        {'title': 'King of Comedy', 'year': '1999'},
        {'title': 'Devils on the Doorstep', 'year': '1999'},
        {'title': 'WALL-E', 'year': '2008'},
        {'title': 'The Pork of Music', 'year': '2012'},
    ]
    user = User(name=name)
    db.session.add(user)
    for m in movies:
        movie = Movie(title=m['title'],year=m['year'])
        db.session.add(movie)

    db.session.commit()
    click.echo('Initialized Database Done')

@app.cli.command()
@click.option("--username",prompt=True,help="The username used to login.")
@click.option("--password",prompt=True,hide_input=True,confirmation_prompt=True,help="The password used to login.")

# @click.option('--username', prompt=True, help='The username used to login.')
# @click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True, help='The password used to login.')
def admin(username,password):
    """ create user """
    db.create_all()

    user = User.query.first()
    if user is not None:
        click.echo("Update User...")
        user.username = username
        user.set_password(password=password)    ## 200310

    else:
        click.echo("Creating User")
        user = User(username=username,name='Admin')
        user.set_password(password=password)
        db.session.add(user)

    db.session.commit()
    click.echo(" ---Done--- ")


## 上下文管理
@app.context_processor
def inject_user():
    user = User.query.first()
    return dict(name=user.name)

@app.errorhandler(404)
def page_not_found(e):
    return render_template('error.html'), 404

## 路由函数: index,edit,delete,login,logout,settings [137- 233]
@app.route('/',methods=['GET','POST'])
def index():
    if request.method == 'POST':
        if not current_user.is_authenticated:
            return redirect(url_for('index'))
        title = request.form.get('title')
        year = request.form.get('year')

        if not title or not year or len(year) > 4 or len(title) > 60:
            flash("Invalid Input ")
            return redirect(url_for('index'))  ## 重定向
        movie = Movie(title=title,year=year)
        db.session.add(movie)
        db.session.commit()
        flash('Item Created')
        return redirect(url_for('index'))

    movies = Movie.query.all()
    return render_template('index.html', movies=movies)

@app.route('/movie/edit/<int:movie_id>',methods=['GET','POST'])
@login_required
def edit(movie_id):
    # movie = Movie.query.get_or_404(movie_id)
    movie = db.session.get(Movie, movie_id)  # 使用 Session.get() 替代 Query.get_or_404
    if not movie:
        return abort(404)  # 如果记录不存在，返回 404 错误
    if request.method == 'POST':
        title = request.form.get('title')
        year = request.form.get('year')

        if not title or not year or len(year) > 4 or len(title) > 60:
            flash("Invalid Input ")
            return redirect(url_for('edit',movie_id=movie_id))  ## 重定向
        movie.title = title
        movie.year = year
        db.session.add(movie)
        db.session.commit()
        flash('Item update')
        return redirect(url_for('index'))  ##重定向到主页面
    return render_template('edit.html', movie=movie)  ##更新编辑页面模板的内容

@app.route('/movie/delete/<int:movie_id>', methods=['POST'])  # 限定只接受 POST 请求
@login_required
def delete(movie_id):
    movie = db.session.get(Movie, movie_id)
    if not movie:
        abort(404)  # 如果记录不存在，返回 404 错误
    db.session.delete(movie)  # 删除对应的记录
    db.session.commit()  # 提交数据库会话
    flash('Item deleted.')
    return redirect(url_for('index'))  # 重定向回主页


@app.route('/login',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        if not username or not password:
            flash('Invalid input ')
            return redirect(url_for('login'))
        
        user = User.query.first()
        if username == user.username and user.validate_password(password):
            login_user(user)
            flash('Successful login ')
            return redirect(url_for('index'))
        
        flash('Invalid username or password ')
        return redirect(url_for('login'))
    
    return render_template('login.html')
        
@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('GoodBye ')
    return redirect(url_for('index'))

@app.route('/setting',methods=['GET','POST'])
def settings():
    if request.method == 'POST':
        name = request.form['name']

        if not name or len(name) > 20:
            flash("Invalid Input ")
            return redirect(url_for('index'))
        
        current_user.name = name
        db.session.commit()
        flash('Setting updated.')
    return render_template('setting.html')



if __name__ == '__main__':
    print("App root path:", app.root_path)
    print("Database URI:", app.config['SQLALCHEMY_DATABASE_URI'])
    app.debug = True
    app.run()
    